#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "lockGuard.hpp"
#include "log.hpp"

const int g_threadNum = 3;

template <class T>
class stdThreadPool
{
public:
    static void *startRoutine(void *args)
    {
        ThreadInfo *threadInfo = (ThreadInfo *)args;
        stdThreadPool<T> *ptrTotp = (stdThreadPool<T> *)threadInfo->_ptrThreadPool;
        while (true)
        {
            T task;
            {
                lockGuard lockguard(ptrTotp->getMutex());
                while (ptrTotp->isTQueueEmpty())
                    ptrTotp->waitCond();
                task = ptrTotp->getTask();
            }
            task(threadInfo->_threadName);
        }
    }

private:
    int _threadNum;
    std::vector<Thread *> _threads;
    std::queue<T> _taskQueue;

    pthread_mutex_t lock;
    pthread_cond_t cond;

public:
    // 构造函数
    stdThreadPool(int threadNum = g_threadNum)
        : _threadNum(threadNum)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);

        for (int i = 1; i <= _threadNum; i++)
        {
            // 初始化列表区域 对象还未存在 走到函数块{}内 对象已存在 可以使用this指针
            _threads.push_back(new Thread(i, startRoutine, this));
        }
    }
    // 启动线程池
    void run()
    {
        for (auto &iter : _threads)
        {
            iter->start();
            logMsg(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
        }
    }
    void pushTask(const T &task)
    {
        lockGuard lockguard(&lock);
        _taskQueue.push(task);
        pthread_cond_signal(&cond);
    }
    // 析构函数
    ~stdThreadPool()
    {
        for (auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
    pthread_mutex_t *getMutex()
    {
        return &lock;
    }
    void waitCond()
    {
        pthread_cond_wait(&cond, &lock);
    }
    bool isTQueueEmpty()
    {
        return _taskQueue.empty();
    }
    T getTask()
    {
        T task = _taskQueue.front();
        _taskQueue.pop();
        return task;
    }
};
